package mi.payment.utils.iso8583;

import android.text.TextUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import mi.payment.utils.ByteUtil;
import mi.payment.utils.NumberUtil;
import sunmi.sunmiui.utils.LogUtil;

/**
 * TLV工具类
 *
 * @author Administrator on 2016/9/5.
 */
public class TLVUtils {

    private final static String TAG = "TLVUtils";

    /**
     * 将16进制字符串转换为TLV对象列表
     */
    public static List<TLV> builderTLVList(String hexString) {
        List<TLV> list = new ArrayList<>();
        int position = 0;
        while (hexString.length() != position) {
            String tag = getTag(hexString, position);
            position += tag.length();
            LPosition l_position = getLengthAndPosition(hexString, position);
            int len = l_position.get_vL();
            position = l_position.get_position();
            String value = hexString.substring(position, position + len * 2);
            position = position + value.length();
            TLV tlv = new TLV(tag, len, value);
            list.add(tlv);
        }
        return list;
    }

    /**
     * 将16进制字符串转换为TLV对象MAP
     */
    public static Map<String, TLV> builderTLVMap(String hexString) {
        // TLV文档连接 http://wenku.baidu.com/view/b31b26a13186bceb18e8bb53.html?re=view&qq-pf-to=pcqq.c2c
        Map<String, TLV> map = new HashMap<>();
        int position = 0;
        while (hexString.length() > position) {
            String tag = getTag(hexString, position);
            if (TextUtils.equals("00", tag)) {
                break;
            }
            position += tag.length();
            LPosition l_position = getLengthAndPosition(hexString, position);
            int len = l_position.get_vL();
            position = l_position.get_position();
            String value = hexString.substring(position, position + len * 2);
            position = position + value.length();
            LogUtil.e(TAG, tag + ": " + value);
            if (map.get(tag) == null && value != null && value.length() > 0) {
                TLV tlv = new TLV(tag, len, value);
                map.put(tag, tlv);
            }
        }
        return map;
    }


    public static Map<String, TLV> builderTLVMap(byte[] hexByte) {
        String hexString = ByteUtil.bytes2HexStr(hexByte);
        return builderTLVMap(hexString);
    }

    /**
     * 将服务器返回的55域TLV 16进制字符串转换为
     * 二次授权处理的数据包含的tag有71，72（可能有多个）发卡行脚本
     * 91 发卡行认证数据
     */
    public static Map<String, String> builderAuthorizationProcessMap(String hexString) {
        Map<String, String> map = new HashMap<>();
        StringBuilder tag71Value = new StringBuilder();
        StringBuilder tag72Value = new StringBuilder();
        StringBuilder tag91Value = new StringBuilder();
        int position = 0;
        while (hexString.length() > position) {
            String tag = getTag(hexString, position);
            if (TextUtils.equals("00", tag)) {
                break;
            }
            position += tag.length();
            LPosition l_position = getLengthAndPosition(hexString, position);
            int len = l_position.get_vL();
            position = l_position.get_position();
            String value = hexString.substring(position, position + len * 2);
            position = position + value.length();
            LogUtil.e(TAG, tag + ": " + value);
            if ("71".equals(tag)) {
                String str = Utils.TLVLengthConversion(len);
                tag71Value.append("71");
                tag71Value.append(str);
                tag71Value.append(value);
            } else if ("72".equals(tag)) {
                tag72Value.append("72");
                String str = Utils.TLVLengthConversion(len);
                tag72Value.append(str);
                tag72Value.append(value);
            } else if ("91".equals(tag)) {
                String str = Utils.TLVLengthConversion(len);
                tag91Value.append("91");
                tag91Value.append(str);
                tag91Value.append(value);
            }
        }
        map.put("71", tag71Value.toString());
        map.put("72", tag72Value.toString());
        map.put("91", tag91Value.toString());
        return map;
    }

    /**
     * 返回最后的Value的长度
     */
    private static LPosition getLengthAndPosition(String hexString, int pos) {
        int position = pos;
        String hexLength;
        String firstByteString = hexString.substring(position, position + 2);
        int i = Integer.parseInt(firstByteString, 16);
        // Length域的编码比较简单,最多有四个字节, 
        // 如果第一个字节的最高位b8为0, b7~b1的值就是value域的长度. 
        // 如果b8为1, b7~b1的值指示了下面有几个子字节. 下面子字节的值就是value域的长度.
        if (((i >> 7) & 1) == 0) {
            hexLength = hexString.substring(position, position + 2);
            position = position + 2;
        } else {
            // 当最左侧的bit位为1的时候，取得后7bit的值，
            int _L_Len = i & 127; // 127的二进制 0111 1111
            position = position + 2;
            hexLength = hexString.substring(position, position + _L_Len * 2);
            // position表示第一个字节，后面的表示有多少个字节来表示后面的Value值
            position = position + _L_Len * 2;
        }

        return new LPosition(Integer.parseInt(hexLength, 16), position);
    }

    /**
     * 取得子域Tag标签
     */
    private static String getTag(String hexString, int position) {
        try {
            String firstByte = hexString.substring(position, position + 2);
            int i = Integer.parseInt(firstByte, 16);
            // b5~b1如果全为1，则说明这个tag下面还有一个子字节，PBOC/EMV里的tag最多占两个字节
            if ((i & 0x1F) == 0x1F) {
                return hexString.substring(position, position + 4);
            } else {
                return hexString.substring(position, position + 2);
            }
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 取得子域Tag标签，Tag标签不仅包含1个字节、2个字节，还包含3个字节。
     */
    public static String getTag1(String hexString, int position) {
        try {
            String firstByte = hexString.substring(position, position + 2);
            int i = Integer.parseInt(firstByte, 16);
            String secondByte = hexString.substring(position + 2, position + 4);
            int j = Integer.parseInt(secondByte, 16);
            // b5~b1如果全为1，则说明这个tag下面还有一个子字节，PBOC/EMV里的tag最多占两个字节
            if ((i & 0x1F) == 0x1F) {
                if ((j & 0x80) == 0x80) { // 除Tag标签首字节外，tag中其他字节最高位为：1-表示后续还有字节；0-表示为最后一个字节。
                    return hexString.substring(position, position + 6); // 3Bytes的tag
                } else {
                    return hexString.substring(position, position + 4); // 2Bytes的tag
                }
            } else {
                return hexString.substring(position, position + 2);
            }
        } catch (Exception e) {
            return "";
        }
    }

    public static String recoveryHexStr(TLV tlv) {
        StringBuilder sb = new StringBuilder();
        sb.append(tlv.getTag());
        int length = tlv.getLength();
        if (length > 127) {
            byte[] bytes = NumberUtil.intToByte4(length);
            int first = -1;
            for (int i = 0; i < bytes.length; i++) {
                if (bytes[i] != 0) {
                    first = i;
                    break;
                }
            }
            bytes = Arrays.copyOfRange(bytes, first, bytes.length);
            int l = (bytes.length | 0x80);
            sb.append(Integer.toHexString(l));
            sb.append(Integer.toHexString(length));
        } else {
            sb.append(Integer.toHexString(length));
        }
        sb.append(Utils.asciiStr2HexStr(tlv.getValue()));
        return sb.toString().toUpperCase();
    }

    /**
     * 将TLV中数据长度转化成16进制字符串
     */
    public static String TLVValueLengthToHexString(int length) {
        if (length <= 0) throw new RuntimeException("不符要求的长度");
        String hexLengthStr = String.format("%02x", length);
        if (length <= 0x7f) {
            return hexLengthStr;
        } else if (length <= 0xff) {
            return "81" + hexLengthStr;
        } else if (length <= 0xffff) {
            return "82" + hexLengthStr;
        } else if (length <= 0xffffff) {
            return "83" + hexLengthStr;
        } else {
            return "TLV 长度最多4个字节";
        }
    }

    public static String TLVRecoveryHexStr(TLV tlv) {
        StringBuilder sb = new StringBuilder();
        String tag = tlv.getTag();
        int length = tlv.getLength();
        String value = tlv.getValue();
        String formatLen = String.format("%04d", length);
        String str2HexStr = Utils.asciiStr2HexStr(value);
        sb.append(tag); // TAG
        sb.append(formatLen); // Length为BCD码
        sb.append(str2HexStr); // Value
        return sb.toString().toUpperCase();
    }

    /**
     * value中有中文
     */
    public static String TLVRecoveryHexStrAtZH(TLV tlv) {
        StringBuilder sb = new StringBuilder();
        String tag = tlv.getTag();
        int length = tlv.getLength();
        String value = tlv.getValue();
        String formatLen = String.format("%04d", length);
        char[] chars = value.toCharArray();
        byte[] chars2Bytes = Utils.chars2Bytes(chars);
        String hexStr = Utils.byte2HexStr(chars2Bytes);
        sb.append(tag); // TAG
        sb.append(formatLen); // Length为BCD码
        sb.append(hexStr);// Value
        return sb.toString().toUpperCase();
    }

}